﻿using System;
using System.Collections.Generic;
using Oxage.Common;
using Oxage.Forms;
using Toub.Sound.Midi;

namespace Oxage.Midi
{
	public class ToubMidiConnector : IConnector
	{
		#region Members
		private WindowsMidiForm form;
		private bool isOpened = false;
		#endregion

		#region Constructor
		public ToubMidiConnector()
		{
			this.MidiPort = 0;
			this.Instrument = 0x01;
			this.LastInputChannel = 0x00;
			this.form = new WindowsMidiForm(this);
		}
		#endregion

		#region Properties
		public int MidiPort
		{
			get;
			set;
		}

		public byte Instrument
		{
			get;
			set;
		}

		public byte LastInputChannel
		{
			get;
			set;
		}
		#endregion

		#region Methods
		public override string ToString()
		{
			return "Toub MIDI";
		}
		#endregion

		#region IConnector Members
		public bool IsOpened
		{
			get
			{
				return this.isOpened;
			}
			set
			{
				this.isOpened = value;
				this.form.IsLocked = value;
			}
		}

		public DataDirection Direction
		{
			get { return DataDirection.Output; }
		}

		public void Open()
		{
			MidiPlayer.OpenMidi(this.MidiPort);
			ProgramChange(this.Instrument);
			this.IsOpened = true;

		}

		public void Close()
		{
			MidiPlayer.CloseMidi();
			this.IsOpened = false;
		}

		public void Send(IMessage message)
		{
			Send(message as MidiMessage);
		}

		public void Send(MidiMessage message)
		{
			if (this.IsOpened && message != null)
			{
				MidiEvent e = null;
				switch (message.Event)
				{
					case MidiEvents.NoteOn:
						e = new NoteOn(0, message.Channel, message.Note, message.Velocity);
						break;

					case MidiEvents.NoteOff:
						e = new NoteOff(0, message.Channel, message.Note, message.Velocity);
						break;

					case MidiEvents.ProgramChange:
						e = new ProgramChange(0, message.Channel, message.Note);
						break;

					case MidiEvents.Aftertouch:
						e = new Aftertouch(0, message.Channel, message.Note, message.Velocity);
						break;
				}
				if (e != null)
				{
					MidiPlayer.Play(e);
					this.LastInputChannel = message.Channel;
				}
			}
		}

		public void ProgramChange(int instrument)
		{
			if (this.IsOpened)
			{
				this.Instrument = (byte)instrument;
				MidiPlayer.Play(new ProgramChange(0, this.LastInputChannel, (byte)instrument));
			}
		}

		public void ProgramChange(MidiProgram program)
		{
			ProgramChange(program.Number);
		}

		public IEnumerable<MidiProgram> GetProgramList()
		{
			return MidiProgram.ConvertList(MidiInfo.Instruments);
		}

		public event EventHandler<EventArgs<IMessage>> Received;
		protected virtual void OnReceived(IMessage message)
		{
			if (Received != null)
			{
				Received(this, new EventArgs<IMessage>(message));
			}
		}

		public IConfigPanel GetConfigPanel()
		{
			return form;
		}
		#endregion
	}
}
